package com.xiaoluo.common.utils;

import com.xiaoluo.cd.entity.base.Jobs;
import com.xiaoluo.cd.entity.base.Projects;
import com.xiaoluo.cd.entity.base.Version;
import com.xiaoluo.common.enums.JobModeEnum;
import com.xiaoluo.common.enums.JobStatusEnum;
import com.xiaoluo.common.queue.BuildLogMap;
import com.xiaoluo.web.form.ProjectForm;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Project : XL-Data
 * Package : com.xiaoluo.common.utils
 * Created by Willian.
 * Date  : 2015/12/2 12:23.
 * 脚本构建
 */
public class Shell {
    private final static Logger logger = LoggerFactory.getLogger(Shell.class);
    private final static String PATH_SUFFIX="_wsp/";
    private final static String SCRIPT_FILE="/fabfile.py";

    /**
     *
     * @param dir
     */
    private static void createWorkSpace(String dir){
        logger.info("createWorkSpace:{}",dir);
        File file = new File(dir);
        if(!file.exists()){
            file.mkdirs();
        }
        createWorkSpaceForce(dir);
    }

    /**
     *
     * @param dir
     * @return
     */
    private static boolean createWorkSpaceForce(String dir){
        logger.info("createWorkSpaceForce:{}",dir);
        ProcessBuilder pb = new ProcessBuilder("mkdir","-p",dir);
        pb.directory(new File("/"));
        pb.redirectErrorStream(true);
        try {
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));
            String line = reader.readLine();

            while (line != null){
                logger.info("exec:{}",line);
                line = reader.readLine();
            }
            int code = process.waitFor();
            logger.info("code:{}",code);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     *
     * @param path
     */
    private static void cleanScript(String path){
        File file = new File(path+SCRIPT_FILE);
        file.delete();
    }
    /**
     *
     * @param projects
     * @param path
     */
    private static void buildScript(ProjectForm projects,Version version,Jobs job,String path,String cmd){

        /**
         * 生成脚本
         */
        try {

            PrintWriter writer = new PrintWriter(new FileOutputStream(path+SCRIPT_FILE));

            Configuration cfg = new Configuration();
            StringTemplateLoader stringLoader = new StringTemplateLoader();
            stringLoader.putTemplate("fabTpl",projects.getScript());
            cfg.setTemplateLoader(stringLoader);

            try {
                Template tpl = cfg.getTemplate("fabTpl");
                Map<String,String> params = new HashMap<String, String>();
                params.put("projectPath",path);
                params.put("projectName",projects.getProjName());
                params.put("gitUrl",projects.getGitSshUrl());
                params.put("remoteDir",projects.getRemoteDir());
                params.put("commitName",job.getCommitName());
                params.put("version",job.getVersionName());
                params.put("uuid",job.getJobName());

                params.put("commitShortName","");//#temp

                if(job.getCommitDate() != null){
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    params.put("commitDate", sdf.format(job.getCommitDate()));
                    sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
                    params.put("commitDateTime", sdf.format(job.getCommitDate()));
                    sdf.applyPattern("HH:mm:ss");
                    params.put("commitTime", sdf.format(job.getCommitDate()));
                }


                if(job.getCommitName() != null){
                    if(job.getCommitName().length()>7){
                        params.put("commitShortName",job.getCommitName().substring(0,7));
                    }
                }

                params.put("remoteDir",projects.getRemoteDir());

                params.put("namespace","default");

                if(job.getJobMode() != null && job.getJobMode()== JobModeEnum.PRERELEASE.getValue()){
                    params.put("namespace","prerelease");
                }
                /**
                 * 生成host信息
                 */
                if(cmd.equals("test")){
                    //test
                    params.put("hosts",projects.getTestServersHost());
                    params.put("passwords",projects.getTestServersPwd());
                }else if(cmd.equals("deploy")){
                    //deploy
                    params.put("hosts",projects.getProductServersHost());
                    params.put("passwords",projects.getProductServersPwd());
                }else{
                    //生产环境构建
                    params.put("hosts",projects.getBuildServersHost());
                    params.put("passwords",projects.getBuildServersPwd());
                }

                //
                params.putAll(parseParameters(version));
                tpl.process(params, writer);
            } catch (TemplateException e) {
                e.printStackTrace();
            }catch (IOException e) {
                e.printStackTrace();
            }

            writer.flush();
            writer.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param version
     * @return
     */
    private static Map<String,String> parseParameters(Version version){
        Map<String,String> paraMap = new HashMap<String, String>();

        if(version != null && version.getChangeLog() != null && !"".equals(version.getChangeLog())){
            String paramters = version.getChangeLog();
            String[] kvs = paramters.split(";");
            if(kvs != null && kvs.length >0){
                for (String kv :kvs){
                    String[] items = kv.split("=");
                    if(items != null && items.length >0){
                        paraMap.put(items[0],items[1]);
                    }
                }
            }
        }

        return paraMap;
    }

    /**
     * 清理目录
     * @param projects
     * @param jobs
     */
    public static void clean(Projects projects,Jobs jobs){
        String path = buildPath(projects,jobs);
        File file = new File(path);
        file.delete();
    }

    private static String buildPath(Projects projects,Jobs jobs){
        String path = ApplicationContextUtils.propertyConfigurer.getProperty("xl.cd.workspace").toString();
        String temp = path+projects.getProjName()+PATH_SUFFIX+jobs.getJobName();
        return temp;
    }
    /**
     *
     * @param projects
     */
    public static void build(ProjectForm projects,Version version,Jobs jobs,String cmd){
        logger.info("run task:{} , project:{}",cmd,projects.getProjName());

        String temp = buildPath(projects,jobs);
        StringBuffer buf = new StringBuffer();

        logger.info("path:{}",temp);

        /**
         * 1、生成代码工作目录；
         * 2、生成构建脚本;
         * 3、运行构建脚本;
         */
        createWorkSpace(temp);
        cleanScript(temp);
        buildScript(projects,version,jobs,temp,cmd);

        ProcessBuilder pb = new ProcessBuilder("fab",cmd);
        pb.directory(new File(temp));
        pb.redirectErrorStream(true);

        try {

            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));

            String line = reader.readLine();

            while (line != null){
                //line = pareseLine(line);
                logger.info(line);
                buf.append(line).append("\r");
                /**
                 * parse line: commitLog
                 */
                if(line.indexOf(getVersionPrefix(projects))>0){
                    String version_ = line.substring(line.lastIndexOf(":") + 1);
                    jobs.setCommitName(version_);
                }
                BuildLogMap.add(jobs.getJobName()+"_"+jobs.getJobType(),line);
                line = reader.readLine();
            }
            process.waitFor(60, TimeUnit.MINUTES);
            jobs.setJobStatus(JobStatusEnum.COMPLETE.getValue());
            //cleanScript(temp);
        } catch (IOException e) {
            e.printStackTrace();
            jobs.setJobStatus(JobStatusEnum.ERROR.getValue());
            buf.append(e.getMessage());
        } catch (InterruptedException e) {
            e.printStackTrace();
            jobs.setJobStatus(JobStatusEnum.ERROR.getValue());
            buf.append(e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            jobs.setJobStatus(JobStatusEnum.ERROR.getValue());
            buf.append(e.getMessage());
        }

        jobs.setJobDesc(buf.toString());
    }

    private static String pareseLine(String line){
        byte[] bytes = line.getBytes();
        /**/
        byte value = 27;
        int index = ArrayUtils.indexOf(bytes,value);

        if(index>0){
            return new String(ArrayUtils.subarray(bytes,0,index));
        }

        return line;
    }


    /**
     *
     * @param projects
     * @return
     */
    private static String getVersionPrefix(ProjectForm projects){
        return projects.getProjName()+"-version:";//msg-version:
    }

}
